﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

using Atosenet.Protocol;
using Atosenet.IO;


namespace Atosenet.IO
{
    public class IOLink : TimingExecutor
    {
        #region 成员

        public readonly static int DEFAULT_READ_TIMEOUT = 2000;

        public event ProtocolPacketReceivedEventHandler PacketReceived;
        public event IOLinkStatusChangedEventHandler IOLinkStatusChanged;
        public event InputDataGeneratedEventHandler InputDataGenerated;
                
        #endregion


        #region 初始化

        public IOLink()
        {
            Init();
        }

        private void Init()
        {
            Init_Component();
            Init_Variable();
        }

        private void Init_Component()
        {
            Receiver = new PacketReceiver(this);
            Sender = new PacketSender(this);
        }

        private void Init_Variable()
        {
            ReadTimeout = DEFAULT_READ_TIMEOUT;
            Status = IOLinkStatus.NotInitialized;
        }

        public bool Initialize(int id, string protocolType)
        {
            return Initialize(id, id, protocolType);
        }

        public bool Initialize(int id, int hostId, string protocolType)
        {
            LinkID = id;
            HostID = hostId;
            ProtocolType = protocolType;
            ProtocolPacket tempPkt = null;
            Status = (id > 0 && ProtocolPacket.TryCreateInstance(protocolType, out tempPkt)) ? IOLinkStatus.Initialized : IOLinkStatus.InitializeFailed;
            OnStatusChanged();
            return id > 0;
        }

        #endregion


        #region 公开函数

        public bool Start()
        {
            if (!IsInitialized || IsStarted)
                return false;

            StartTimer();
            Receiver.Start(0);
            Sender.Start(0);
            ChangeStatus(IOLinkStatus.Stoped, IOLinkStatus.Started);
            return true;
        }

        public bool Stop()
        {
            if (!IsInitialized || !IsStarted)
                return false;

            StopTimer();
            Receiver.Stop();
            Sender.Stop();
            ChangeStatus(IOLinkStatus.Started, IOLinkStatus.Stoped);
            return true;
        }

        public IProtocolPacket[] GetAllPackets()
        {
            return Receiver.GetAllPackets();
        }

        public bool GetOnePacket(out IProtocolPacket packet)
        {
            return Receiver.GetPacket(out packet);
        }

        public bool SendPacket(IProtocolPacket packet)
        {
            if (!IsInitialized || !IsStarted)
                return false;

            byte[] pData = packet.Generate();
            return SendData(pData);
        }

        public bool SendData(byte[] data)
        {
            if (data == null || data.Length == 0)
                return false;

            Sender.Execute(data);
            return true;
        }

        public bool InputData(byte[] data)
        {
            if (!IsInitialized || !IsStarted || data == null)
                return false;

            Receiver.Execute(data);
            return true;
        }

        public override bool Equals(object obj)
        {
            IOLink link = obj as IOLink;

            if (link == null)
                return false;

            return this.LinkID.Equals(link.LinkID);
        }

        public override int GetHashCode()
        {
            return this.LinkID.GetHashCode();
        }

        #endregion


        #region 核心函数

        protected override void WorkThreadMethod()
        {
            CountDataParameters();
        }

        private void CountDataParameters()
        {
            this.ReceiveSpeed = (float)(Receiver.TotalDataFlow - this.TotalReceivedBytes);
            this.SendSpeed = (float)(Sender.TotalDataFlow - this.TotalSentBytes);
            this.TotalReceivedBytes = Receiver.TotalDataFlow;
            this.TotalSentBytes = Sender.TotalDataFlow;
        }

        private void RemoveStatus(IOLinkStatus sts)
        {
            Status = Status & (~sts);
        }

        private void AddStatus(IOLinkStatus sts)
        {
            Status = Status | sts;
        }

        private bool ContainStatus(IOLinkStatus sts)
        {
            return (Status & sts) != 0;
        }

        private void ChangeStatus(IOLinkStatus targetStatus, IOLinkStatus toModifyStatus)
        {
            RemoveStatus(targetStatus);
            AddStatus(toModifyStatus);
        }

        #endregion


        #region 属性

        public bool IsStarted
        {
            get { return ContainStatus(IOLinkStatus.Started); }
        }

        public bool IsInitialized
        {
            get { return !ContainStatus(IOLinkStatus.NotInitialized) && !ContainStatus(IOLinkStatus.InitializeFailed); }
        }

        public IOLinkStatus Status
        {
            get;
            private set;
        }

        private PacketReceiver Receiver
        {
            get;
            set;
        }

        private PacketSender Sender
        {
            get;
            set;
        }

        public int LinkID
        {
            get;
            private set;
        }

        public int HostID
        {
            get;
            private set;
        }

        public bool IsClientLink
        {
            get { return LinkID != HostID; }
        }

        public long TotalReceivedBytes
        {
            get;
            private set;
        }

        public long TotalSentBytes
        {
            get;
            private set;
        }

        public float ReceiveSpeed
        {
            get;
            private set;
        }

        public float SendSpeed
        {
            get;
            private set;
        }

        public int CurrentRawDataCount
        {
            get
            {
                return Receiver.CurrentTaskCount;
            }
        }

        public int ReceivedQueueCount
        {
            get
            {
                return Receiver.CurrentTaskCount;
            }
        }

        public long ReceivedCount
        {
            get { return Receiver.ExecutedCount; }
        }

        public long SentCount
        {
            get { return Sender.ExecutedCount; }
        }

        public int SendQueueCount
        {
            get
            {
                return Sender.CurrentTaskCount;
            }
        }

        public int ReadTimeout
        {
            get;
            set;
        }

        public string ProtocolType
        {
            get;
            private set;
        }

        #endregion


        #region 事件

        private void OnStatusChanged()
        {
            if (IOLinkStatusChanged != null)
            {
                IOLinkStatusChanged(this, new IOLinkStatusChangedEventArgs(Status, LinkID, HostID));
            }
        }

        private void OnProtocolPacketReceived()
        {
            if (PacketReceived != null)
            {
                ProtocolPacketReceivedEventArgs e = new ProtocolPacketReceivedEventArgs(LinkID, HostID);
                PacketReceived(this, e);
            }
        }

        private void OnInputDataGenerated(byte[] data)
        {
            if (InputDataGenerated != null)
            {
                InputDataGeneratedEventArgs e = new InputDataGeneratedEventArgs(data, LinkID, HostID);
                InputDataGenerated(this, e);
            }
        }

        #endregion


        #region 附加类

        internal class PacketReceiver : SingleExecuteQueue<byte[]>
        {
            #region 初始化

            public PacketReceiver(IOLink parent)
            {
                Parent = parent;
                Init();
            }

            private void Init()
            {
                Init_Component();
                Init_Variable();
            }

            private void Init_Component()
            {
                ReceivedPackets = new List<IProtocolPacket>();
            }

            private void Init_Variable()
            {
                Timestamp = DateTime.MinValue;
            }

            #endregion


            #region 公开函数

            public IProtocolPacket[] GetAllPackets()
            {
                IProtocolPacket[] result = null;

                lock (ReceivedPackets)
                {
                    result = ReceivedPackets.ToArray();
                    ReceivedPackets.Clear();
                }
                return result;
            }

            public bool GetPacket(out IProtocolPacket pkt)
            {
                pkt = null;

                if (ReceivedPackets.Count <= 0)
                    return false;

                lock (ReceivedPackets)
                {
                    pkt = ReceivedPackets[0];
                    ReceivedPackets.RemoveAt(0);
                }
                return pkt != null;
            }

            #endregion


            #region 核心函数

            protected override bool ExecutingProcess(byte[] data)
            {
                int offset = 0;

                do
                {
                    Parent.RemoveStatus(IOLinkStatus.ErrorOccured);
                    Parent.RemoveStatus(IOLinkStatus.Timeout);
                    Parent.ChangeStatus(IOLinkStatus.Received, IOLinkStatus.Receiving);
                    Parent.OnStatusChanged();

                    if (CurrentPacket == null)
                    {
                        /* 动态构造协议包类型 */
                        ProtocolPacket pkt = null;

                        if (ProtocolPacket.TryCreateInstance(Parent.ProtocolType, out pkt))
                            CurrentPacket = pkt;
                        else
                            return false;

                        Timestamp = DateTime.Now;
                    }

                    TotalDataFlow += data.Length;
                    CurrentPacket.Append(data, ref offset);

                    if (CurrentPacket.IsCompleted)
                    {
                        IProtocolPacket packet = CurrentPacket.Clone() as IProtocolPacket;

                        lock (ReceivedPackets)
                        {
                            ReceivedPackets.Add(packet);
                        }
                        CurrentPacket = null;
                        Parent.ChangeStatus(IOLinkStatus.Receiving, IOLinkStatus.Received);
                        Parent.OnStatusChanged();
                        Parent.OnProtocolPacketReceived();
                    }

                    /* 组包超时机制，当组包出现死循环时，可以在此退出流程 */
                    if ((int)((DateTime.Now - Timestamp).TotalMilliseconds) >= Parent.ReadTimeout)
                    {
                        CurrentPacket = null;
                        Parent.AddStatus(IOLinkStatus.Timeout);
                        Parent.OnStatusChanged();
                        return false;
                    }
                }
                while (offset < data.Length);
                return true;
            }

            protected override bool VerifyData(byte[] data)
            {
                return data != null && data.Length != 0;
            }

            #endregion


            #region 属性

            private IProtocolPacket CurrentPacket
            {
                get;
                set;
            }

            public IOLink Parent
            {
                get;
                private set;
            }

            public List<IProtocolPacket> ReceivedPackets
            {
                get;
                private set;
            }

            public long TotalDataFlow
            {
                get;
                private set;
            }

            public DateTime Timestamp
            {
                get;
                private set;
            }

            #endregion
        }

        internal class PacketSender : SingleExecuteQueue<byte[]>
        {
            #region 初始化

            public PacketSender(IOLink parent)
            {
                Parent = parent;
            }

            #endregion


            #region 核心函数

            protected override bool ExecutingProcess(byte[] data)
            {
                if (data == null || data.Length == 0)
                    return false;

                TotalDataFlow += data.Length;
                Parent.OnInputDataGenerated(data);
                return true;
            }

            protected override bool VerifyData(byte[] data)
            {
                return data != null && data.Length != 0;
            }

            #endregion


            #region 属性

            public IOLink Parent
            {
                get;
                private set;
            }

            public long TotalDataFlow
            {
                get;
                private set;
            }

            #endregion
        }

        #endregion
    }


    public delegate void ProtocolPacketReceivedEventHandler(object sender, ProtocolPacketReceivedEventArgs e);

    public class ProtocolPacketReceivedEventArgs : EventArgs
    {
        public DateTime Timestamp;
        public int LinkID;
        public int HostID;

        public ProtocolPacketReceivedEventArgs(int linkId, int hostId)
        {
            HostID = hostId;
            Timestamp = DateTime.Now;
            LinkID = linkId;
        }
    }

    //public delegate void RawDataReceivedEventHandler(object sender);

    //public class RawDataReceivedEventArgs : EventArgs
    //{
    //    public DateTime Timestamp;
    //    public int LinkID;
    //    public int HostID;
    //    public byte[] Data;

    //    public RawDataReceivedEventArgs(int linkId, int hostId, byte data)
    //    {
    //        HostID = hostId;
    //        Timestamp = DateTime.Now;
    //        LinkID = linkId;
    //    }
    //}

    public delegate void InputDataGeneratedEventHandler(object sender, InputDataGeneratedEventArgs e);

    public class InputDataGeneratedEventArgs : EventArgs
    {
        public byte[] Data;
        public int LinkID;
        public int HostID;
        public DateTime Timestamp;

        public InputDataGeneratedEventArgs(byte[] data, int id, int hostId)
        {
            HostID = hostId;
            Data = data;
            LinkID = id;
        }
    }

    [Flags]
    public enum IOLinkStatus
    {
        NotInitialized = 0x01,
        InitializeFailed = 0x02,
        Initialized = 0x04,
        Started = 0x08,
        Receiving = 0x10,
        Received = 0x20,
        ErrorOccured = 0x40,
        Timeout = 0x80,
        Paused = 0x100,
        Stoped = 0x200
    }

    public delegate void IOLinkStatusChangedEventHandler(object sender, IOLinkStatusChangedEventArgs e);

    public class IOLinkStatusChangedEventArgs : EventArgs
    {
        public IOLinkStatus Status;
        public int LinkID;
        public int HostID;
        public DateTime Timestamp;

        public IOLinkStatusChangedEventArgs(IOLinkStatus status, int linkId, int hostId)
        {
            HostID = hostId;
            LinkID = linkId;
            Status = status;
            Timestamp = DateTime.Now;
        }
    }
}
